package api

import (
	"context"
	"fmt"
	"regexp"

	controller "gitee.com/klein-x/biz/controller/user"
	"gitee.com/klein-x/biz/xutils"
	"github.com/cloudwego/hertz/pkg/app"
)

var passwordRegexpNum = regexp.MustCompile(`[*0-9]`)
var passwordRegexpLower = regexp.MustCompile(`[*a-z]`)
var passwordRegexpUpper = regexp.MustCompile(`[*A-Z]`)
var passwordRegexpSpecial = regexp.MustCompile(`[_!@#$%^&~()-+=]`)

type registerRequest struct {
	Version  Version `path:"version" vd:"in($, 1, 2); msg:'未定义的请求'"`
	PhoneID  string  `form:"phone" json:"phone" vd:"phone($, 'CN'); msg:'无效的手机号码'"`
	Password string  `form:"password" json:"password" vd:"len($)>=8 && len($)<=16; msg:'无效的密码'"`
	Captcha  string  `form:"captcha" json:"captcha" vd:"len($)==4; msg:'无效的验证码'"`
}

// 注册用户
func UserRegister(ctx context.Context, c *app.RequestContext) {
	var req registerRequest
	if err := c.BindAndValidate(&req); err != nil {
		ReturnError(c, xutils.Error(API_PARAM_ERROR, err))
		return
	}

	if err := CheckPassword(req.Password); err != nil {
		ReturnError(c, xutils.Error(API_PARAM_ERROR, err))
		return
	}

	if err := controller.Register(ctx, req.PhoneID, req.Password, req.Captcha); err != nil {
		ReturnError(c, err)
		return
	}
	ReturnSuccess(c, nil)
}

func CheckPassword(pwd string) error {
	// 检查密码是否匹配正则表达式
	var matchStep = 0
	if passwordRegexpNum.MatchString(pwd) {
		matchStep++
	}
	if passwordRegexpLower.MatchString(pwd) {
		matchStep++
	}
	if passwordRegexpUpper.MatchString(pwd) {
		matchStep++
	}
	if passwordRegexpSpecial.MatchString(pwd) {
		matchStep++
	}
	if matchStep < 3 {
		return fmt.Errorf("密码校验失败,应至少三种元素(大写、小写、数字、特殊字符)")
	}
	return nil
}

// 修改密码
type updatePasswordRequest registerRequest

func UpdatePassword(ctx context.Context, c *app.RequestContext) {
	var req updatePasswordRequest
	if err := c.BindAndValidate(&req); err != nil {
		ReturnError(c, xutils.Error(API_PARAM_ERROR, err))
		return
	}

	if err := CheckPassword(req.Password); err != nil {
		ReturnError(c, xutils.Error(API_PARAM_ERROR, err))
		return
	}

	if err := controller.UpdatePassword(ctx, req.PhoneID, req.Password, req.Captcha); err != nil {
		ReturnError(c, err)
		return
	} else {
		ReturnSuccess(c, nil)
	}
}

type updateUsernameRequest struct {
	Version  Version `path:"version" vd:"in($, 1, 2); msg:'未定义的请求'"`
	Username string  `form:"name" json:"name" vd:"len($)<=60; msg:'用户名长度不符合要求'"`
}

func UpdateUsername(ctx context.Context, c *app.RequestContext) {
	var req updateUsernameRequest
	if err := c.BindAndValidate(&req); err != nil {
		ReturnError(c, xutils.Error(API_PARAM_ERROR, err))
		return
	}

	uid := c.GetString("id")

	if err := controller.UpdateUsername(ctx, uid, req.Username); err != nil {
		ReturnError(c, err)
		return
	} else {
		ReturnSuccess(c, nil)
	}
}

func GetUser(ctx context.Context, c *app.RequestContext) {
	uid := c.GetString("id")
	userInfo, err := controller.GetUser(ctx, uid)
	if err != nil {
		ReturnError(c, err)
	} else {
		ReturnSuccess(c, userInfo)
	}
}

type loginRequest struct {
	Version  Version `path:"version" vd:"in($, 1, 2); msg:'未定义的请求'"`
	Type     string  `form:"type" json:"type" vd:"in($, 'password', 'captcha'); msg:'无效的登录类型'"`
	PhoneID  string  `form:"phone" json:"phone" vd:"phone($, 'CN'); msg:'无效的手机号码'"`
	Password string  `form:"password" json:"password" vd:"(Type)$!='password' || len($)>=8 && len($)<=16; msg:'无效的密码'"`
	Captcha  string  `form:"captcha" json:"captcha" vd:"(Type)$!='captcha' || len($)==4; msg:'无效的验证码'}"`
}

// 登录验证用户名密码
func Login(ctx context.Context, c *app.RequestContext) (interface{}, error) {
	var req loginRequest
	if err := c.BindAndValidate(&req); err != nil {
		if err.Error() == "无效的密码" {
			ReturnLogin(c, xutils.Error(4006, "密码错误")) // 登录时规则验证错误 返回密码错误
		} else {
			ReturnLogin(c, xutils.Error(API_PARAM_ERROR, err))
		}

		return nil, err
	}
	switch req.Type {
	case "password":
		if err := CheckPassword(req.Password); err != nil {
			ReturnLogin(c, xutils.Error(4006, "密码错误")) // 登录时规则验证错误 返回密码错误
			return nil, err
		}
		if data, err := controller.LoginWithPassword(req.PhoneID, req.Password); err != nil {
			ReturnLogin(c, err)
			return nil, err
		} else {
			return data, nil
		}
	case "captcha":
		if data, err := controller.LoginWithCaptcha(ctx, req.PhoneID, req.Captcha); err != nil {
			ReturnLogin(c, err)
			return nil, err
		} else {
			return data, nil
		}
	default:
		ReturnLogin(c, xutils.Error(API_PARAM_ERROR, fmt.Errorf("无效的登录类型")))
		return nil, fmt.Errorf("无效的登录类型")
	}
}

type refreshRequest struct {
	Version     Version `path:"version" vd:"in($, 1, 2); msg:'未定义的请求'"`
	AccessToken string  `form:"access_token" json:"access_token" vd:"regexp('^(.*\\.){2}.*$'); msg:'无效的token'"`
}

func Refresh(ctx context.Context, c *app.RequestContext) (string, error) {
	var req refreshRequest
	if err := c.BindAndValidate(&req); err != nil {
		return "", err
	}

	//TODO: 检验redis中有没有匹配的 accessToken？
	return req.AccessToken, nil
}
